package com.xpec.c4.game.common;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.Set;
import java.util.UUID;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.xpec.c4.game.utility.GUID;
import com.xpec.c4.service.module.common.PlayerCommonInfoManager;

/**
 * 辅助类
 * 
 * @author Bany
 * 
 * @since 2009-4-2 下午11:49:55
 * 
 */

public class Helper {
	/**浮點小數位數處理**/
	public static final int VALUE_SCALE = 2;
	
	
	private static final Log log = LogFactory.getLog(Helper.class);

	private static ThreadLocal<Random> random = new ThreadLocal<Random>();

	public static Random getRandom() {
		Random r = random.get();
		if (r == null) {
			r = new Random();
			random.set(r);
		}
		return r;
	}


	/**
	 * 生成范围内的随机数
	 * 
	 * @param min
	 *            最小（包含）
	 * @param max
	 *            最大（不包含）
	 * @return 随机数
	 */
	public static int randomInt(int min, int max) {
		if (min == max) {
			return min;
		} 
		else {
			if (max < min) {
				int temp = max;
				max = min;
				min = temp;
			}
			int result = getRandom().nextInt(max - min);
			result += min;
			return result;
		}
	}
	
	/**
	 * 隨機一個0~(max-1)的long
	 * @param min
	 * @param max
	 * @return
	 */
	public static long randomLong(long min, long max)
	{
		if(min == max)
		{
			return min;
		}
		else
		{
			if(max < min)
			{
				long temp = max;
				max = min;
				min = temp;
			}
			
			long result = min + (long) (getRandom().nextDouble() * (max - min));
			return result;
		}
	}
	/**
	 * 生成范围内的随机数
	 * 
	 * @param min
	 *            最小（包含）
	 * @param max
	 *            最大（不包含）
	 * @return 随机数
	 */
	public static float randomFloat(float min, float max) {
		if (min == max) {
			return min;
		} else {
			
			float result = ((float)getRandom().nextInt( (int)((max*1000) - (min*1000)) )) / 1000.0f;
			result += min;
			return result;
		}
	}
	/**
	 * 生成范围内的随机数
	 * 
	 * @param min
	 *            最小（包含）
	 * @param max
	 *            最大（包含）
	 * @return 随机数
	 * 
	 * wuweijun add
	 */
	public static float randomFloatIncludeMax(float min, float max) {
		if (min == max) {
			return min;
		} else {
			
			float result = ((float)getRandom().nextInt( (int)((max *1000 + 1) - (min*1000)) )) / 1000.0f;
			result += min;
			return result;
		}
	}

	/**
	 * 生成随机数
	 * 
	 * @param min
	 *            最小（包含）
	 * @param max
	 *            最大（不包含）
	 * @return 随机数
	 */
	public static int randomInt() {
		return getRandom().nextInt();
	}

	/**
	 * 按精度取值
	 * 
	 * @param v
	 * @param scale
	 * @return
	 */
	public static float numberFormat(float v, int scale) {
		BigDecimal bd = new BigDecimal(v);
		bd = bd.setScale(scale, BigDecimal.ROUND_HALF_UP);
		return bd.floatValue();
	}

	/**
	 * 得到随机的中文字符串
	 * 
	 * @param size
	 *            长度
	 * @return
	 */
	public static String getRandomChineseString(int size) {
		StringBuffer cs = new StringBuffer();
		for (int i = 0; i < size; i++) {
			cs.append((char) randomInt(20000, 40000));
		}
		return cs.toString();
	}

	/**
	 * 产生唯一的ID值。 使用UUID
	 * 
	 * @return
	 */
	public static String getUniqueID() {
		return UUID.randomUUID().toString();
	}

	/**
	 * 产生唯一的ID值，并指定前缀
	 * 
	 * @param pix
	 *            前缀
	 * @return
	 */
	public static String getUniqueID(String pix) {
		return pix + "_" + getUniqueID();
	}

	/**
	 * 通过essionID获得IP
	 * 
	 * @param sessionID
	 * @return
	 * 
	 * @author lipeilin
	 * @2011-3-27 下午06:05:16
	 */
	public static String getIP(GUID sessionID) {
		if(sessionID == null){
			return null;
		}
		return PlayerCommonInfoManager.getInstance().getClientIpBySessionId(sessionID);
		
//		// IP是否允许
//		String ip = sessionID;
//		// Helper
//		ip = ip.substring(ip.indexOf("/") + 1, ip.indexOf(":"));
//		return ip;
	}

	/**
	 * 获得随机数
	 * 
	 * @return 0.0 ～ 1.0
	 */
	public static float randomFloat() {
		return getRandom().nextFloat();
	}

	/**
	 * 获得随机BOOLEAN
	 * 
	 * @return
	 * 
	 * @2011-8-15 下午06:41:37
	 */
	public static boolean randomBoolean() {
		return getRandom().nextBoolean();
	}
	
	/**
	 * 取精度
	 * @param value
	 * @return
	 */
	public static float floatPrecision(float value){
		return ( Math.round((value) * 100000d)) / 100000f;
	}
	
	/**
	 * 取精度
	 * @param value
	 * @return
	 */
	public static double doublePrecision(double value){
		return ( Math.round((value) * 100000d)) / 100000d;
	}

	/**
	 * 取指定精度
	 * @param value
	 * @param prec 小数点以下5位就填 100000
	 * @return
	 */
	public static float floatPrecision(float value, float prec){
		return ( Math.round((value) * prec)) / prec;
	}
	
	/**
	 * 取指定精度
	 * @param value
	 * @param prec 小数点以下5位就填 100000
	 * @return
	 */
	public static double doublePrecision(double value, double prec){
		return ( Math.round((value) * prec)) / prec;
	}

	/**
	 * 按照权重列表中的权重挑出指定数目的元素<br>
	 * 
	 * @param <T>
	 *            元素类型
	 * @param num
	 *            指定数目
	 * @param weightMap
	 *            权重列表
	 * @return 返回挑出的元素
	 * 
	 * @author suyinglong
	 * @version 2011-8-17 下午03:03:39
	 */
	public static <T> List<T> getListByWeight(int num, Map<String, T> weightMap) {
		ArrayList<T> list = new ArrayList<T>();
		int total = 0;
		int weight = 0;
		HashMap<String, T> weightMapCopy = new HashMap<String, T>(weightMap);

		int temp = 0;
		int randomNumber = 0;
		String key = null;
		Set<Entry<String, T>> entrySet = null;
		for (int i = 0; i < num; i++) {
			for (String w : weightMapCopy.keySet()) {
				if (w != null) {
					weight = Integer.parseInt(w);
					if (weight > 0) {
						total += weight;
					}
				}
			}
			randomNumber = randomInt(0, total);
			entrySet = weightMapCopy.entrySet();
			for (Entry<String, T> entry : entrySet) {
				key = entry.getKey();
				if (key != null) {
					weight = Integer.parseInt(key);
					if (weight > 0) {
						temp += weight;
						if (randomNumber < temp) {
							list.add(entry.getValue());
							weightMapCopy.remove(key);
							break;
						}
					} else if (weight < 0) {
						list.add(entry.getValue());
						weightMapCopy.remove(key);
						break;
					}
				} else {
					weightMapCopy.remove(key);
				}
			}
		}

		return list;
	}
	
	public static String timeFormat(long timeInMillis){
		Calendar c = Calendar.getInstance();
		c.setTimeInMillis(timeInMillis);
		StringBuilder sb = new StringBuilder();
		sb.append(c.get(Calendar.HOUR_OF_DAY)).append(":");
		sb.append(c.get(Calendar.MINUTE)).append(":");
		sb.append(c.get(Calendar.SECOND)).append(":");
		
		return sb.toString();
	}
	/**
	 * 從數據Hashmap裡面取出upperbound的欄位
	 * @param compareValue
	 * @param findMap
	 * @return
	 */
	public static <T> T getMapKeyUpperBoundValue(int compareValue, HashMap<String , T> findMap){
		return getMapKeyUpperBoundValue(compareValue, findMap, false);
	}
	
	/**
	 * 從數據Hashmap裡面取出upperbound的欄位
	 * @param compareValue
	 * @param findMap
	 * @return
	 */
	public static <T> T getMapKeyUpperBoundValue(int compareValue, HashMap<String , T> findMap, boolean takeLastWhenNothing){
		if(findMap == null) return null;
		ArrayList<Integer> compareList = new ArrayList<Integer>();
		//先比較等級區間
		int keyIntValue; 
		for (String key : findMap.keySet()) {
			try {
				keyIntValue = Integer.parseInt(key);
				compareList.add(keyIntValue);
			} catch (RuntimeException e) {
				e.printStackTrace();
				return null;
			}
		}
		Collections.sort(compareList);
		for (Integer ratioIntValue : compareList) {
			if (compareValue <= ratioIntValue) {
				return findMap.get(String.valueOf(ratioIntValue));
			}
		}
		
		if(takeLastWhenNothing && compareList.size() > 0)
		{
			return findMap.get(compareList.get(compareList.size() - 1));
		}
		
		return null;
	}
	
	public static int intCompare(int value1, int value2){
		if(value1 == value2)
			return 0;
		else if(value1 > value2)
			return -1;
		else
			return 1;
	}
	public static int longCompare(long value1, long value2){
		if(value1 == value2)
			return 0;
		else if(value1 > value2)
			return -1;
		else
			return 1;
	}
	/**
	 * merge map1 的資料到map2 ,相同key的value會相加
	 * @param map1
	 * @param map2
	 */
	public static void mergeStringIntegerMap(HashMap<String ,Integer> map1 , HashMap<String ,Integer> map2){
		if(map1 == null)
			return;
		for(Entry<String,Integer> node : map1.entrySet()){
			if(!map2.containsKey(node.getKey()))
				map2.put(node.getKey(), node.getValue());
			else{
				map2.put(node.getKey(), node.getValue() + map2.get(node.getKey()));
			}
		}
	}
	/**
	 * 針對array可任意insert 某個index 的value , 但是  index > 目前size  < index 之前會填滿defaultValue
	 * 
	 * Ps. default盡量用基礎類別, 如果是自定義類別的話, defaultValue會是同一個reference (泛型類還不給clone Orz), 基礎類不會有refrence的問題
	 * @param appendList
	 * @param index
	 * @param value
	 * @param defaultValue
	 */
	public static <T> void insertListValueWithFillDefault(List<T> appendList, int index, T value , T defaultValue){
		if(appendList == null) return;
		
		if(index < appendList.size()){
			appendList.set(index, value);
		}
		else{
			while(appendList.size() < index )
				appendList.add(defaultValue == null ? null : defaultValue);
			appendList.add(value);
		}
	}
	
	/**
	 * 兩個long值用在排序時使用 (防止overflow)
	 * @param value1
	 * @param value2
	 * @return
	 */
	public static int getSortOrder(long value1, long value2)
	{
		if(value1 > value2)
		{
			return 1;
		}
		else if(value1 < value2)
		{
			return -1;
		}
		else
		{
			return 0;
		}
	}

	/**
	 * 獲得整數上限
	 * 
	 * @param totalValue
	 * @param divider
	 * @return
	 */
	public static int getCeil(int totalValue, int divider)
	{
		return (totalValue + (divider -1)) / divider;
	}
	
	/**
	 * 獲得整數上限
	 * 
	 * @param totalValue
	 * @param divider
	 * @return
	 */
	public static long getCeil(long totalValue, long divider)
	{
		return (totalValue + (divider -1)) / divider;
	}
	
	/**
	 * 產生到期時間
	 * 
	 * @param currentTime
	 * @param duration
	 * @param timeUnit
	 * @return
	 */
	public static long generateExpirationTime(long currentTime, long duration, long timeUnit)
	{
		if(duration <= 0)
		{
			return Long.MAX_VALUE;
		}
		else
		{
			return currentTime + duration * timeUnit;
		}
	}
	
	/**
	 * 高精準度 - 加法(小數四位 ，無條位進位)
	 * @param value1
	 * @param value2
	 * @return
	 */
	public static BigDecimal add(double value1,double value2)
	{
		         BigDecimal b1 = new BigDecimal(String.valueOf(value1));
		         BigDecimal b2 = new BigDecimal(String.valueOf(value2));
		         return b1.add(b2).setScale(VALUE_SCALE,BigDecimal.ROUND_DOWN);
	}
	
	/**
	 * 高精準度 - 加法(小數四位 ，無條位進位)
	 * @param value1
	 * @param value2
	 * @return
	 */
	public static BigDecimal add(long value1,long value2)
	{
		         BigDecimal b1 = new BigDecimal(Long.valueOf(value1));
		         BigDecimal b2 = new BigDecimal(Long.valueOf(value2));
		         return b1.add(b2).setScale(VALUE_SCALE,BigDecimal.ROUND_DOWN);
	}
	
	/**
	 * 高精準度 - 加法(小數四位 ，無條位進位)
	 * @param value1
	 * @param value2
	 * @return
	 */
	public static BigDecimal add(BigDecimal value1,BigDecimal value2)
	{
		         return value1.add(value2).setScale(VALUE_SCALE,BigDecimal.ROUND_DOWN);
	}
	
	
	/**
	 * 高精準度 -乘法(小數四位 ，無條位進位)
	 * @param value1
	 * @param value2
	 * @return
	 */
	public static BigDecimal mul(double value1,double value2)
	{	
	         BigDecimal b1 = new BigDecimal(String.valueOf(value1));
		     BigDecimal b2 = new BigDecimal(String.valueOf(value2));
		     return b1.multiply(b2).setScale(VALUE_SCALE,BigDecimal.ROUND_DOWN);
	}
	
	/**
	 * 高精準度 -乘法(小數四位 ，無條位進位)
	 * @param value1
	 * @param value2
	 * @return
	 */
	public static BigDecimal mul(long value1,long value2)
	{
	         BigDecimal b1 = new BigDecimal(Long.valueOf(value1));
		     BigDecimal b2 = new BigDecimal(Long.valueOf(value2));
		     return b1.multiply(b2).setScale(VALUE_SCALE,BigDecimal.ROUND_DOWN);
	}
	
	/**
	 * 高精準度 -乘法(小數四位 ，無條位進位)
	 * @param value1
	 * @param value2
	 * @return
	 */
	public static BigDecimal mul(BigDecimal value1, BigDecimal value2) {
		return value1.multiply(value2).setScale(VALUE_SCALE, BigDecimal.ROUND_DOWN);
	}
	
	
	/**
	 * 高精準度 -除法(小數四位 ，無條位進位)
	 * @param value1
	 * @param value2
	 * @return
	 */
	public static BigDecimal div(double value1,double value2)
	{
		BigDecimal b1 = new BigDecimal(String.valueOf(value1));
		BigDecimal b2 = new BigDecimal(String.valueOf(value2));
		if (isEqual(b2, BigDecimal.ZERO)) {
			return BigDecimal.ZERO;
		}

		return b1.divide(b2, VALUE_SCALE, BigDecimal.ROUND_DOWN);
	}
	
	/**
	 * 高精準度 -除法(小數四位 ，無條位進位)
	 * @param value1
	 * @param value2
	 * @return
	 */
	public static BigDecimal div(long value1,long value2)
	{
		BigDecimal b1 = new BigDecimal(Long.valueOf(value1));
		BigDecimal b2 = new BigDecimal(Long.valueOf(value2));
		if (isEqual(b2, BigDecimal.ZERO)) {
			return BigDecimal.ZERO;
		}

		return b1.divide(b2, VALUE_SCALE, BigDecimal.ROUND_DOWN);
	}
	
	/**
	 * 高精準度 -除法(小數四位 ，無條位進位)
	 * @param value1
	 * @param value2
	 * @return
	 */
	public static BigDecimal div(BigDecimal value1,BigDecimal value2)
	{
		if (isEqual(value2, BigDecimal.ZERO)) {
			return BigDecimal.ZERO;
		}

		return value1.divide(value2, VALUE_SCALE, BigDecimal.ROUND_DOWN);
	}
	
	
	/**
	 * 高精準度 -減法(小數四位 ，無條位進位)
	 * @param value1
	 * @param value2
	 * @return
	 */
	public static BigDecimal sub(double value1,double value2)
	{
	         BigDecimal b1 = new BigDecimal(String.valueOf(value1));
		     BigDecimal b2 = new BigDecimal(String.valueOf(value2));
		     return b1.subtract(b2).setScale(VALUE_SCALE,BigDecimal.ROUND_DOWN);
	}
	
	/**
	 * 高精準度 -減法(小數四位 ，無條位進位)
	 * @param value1
	 * @param value2
	 * @return
	 */
	public static BigDecimal sub(long value1,long value2)
	{
	         BigDecimal b1 = new BigDecimal(Long.valueOf(value1));
		     BigDecimal b2 = new BigDecimal(Long.valueOf(value2));
		     return b1.subtract(b2).setScale(VALUE_SCALE,BigDecimal.ROUND_DOWN);
	}
	
	/**
	 * 高精準度 -減法(小數四位 ，無條位進位)
	 * @param value1
	 * @param value2
	 * @return
	 */
	public static BigDecimal sub(BigDecimal value1,BigDecimal value2)
	{
		     return value1.subtract(value2).setScale(VALUE_SCALE,BigDecimal.ROUND_DOWN);
	}

	/**
	 * value1 是否大於 value2
	 */
	public static boolean isGreater(BigDecimal value1, BigDecimal value2) {
		return (value1.compareTo(value2) > 0);
	}

	/**
	 * value1 是否大於等於 value2
	 */
	public static boolean isGreaterEqual(BigDecimal value1, BigDecimal value2) {
		return (value1.compareTo(value2) >= 0);
	}

	/**
	 * value1 是否等於 value2
	 */
	public static boolean isEqual(BigDecimal value1, BigDecimal value2) {
		return (value1.compareTo(value2) == 0);
	}

	/**
	 * value1 是否小於等於 value2
	 */
	public static boolean isLessEqual(BigDecimal value1, BigDecimal value2) {
		return (value1.compareTo(value2) <= 0);
	}

	/**
	 * value1 是否小於 value2
	 */
	public static boolean isLess(BigDecimal value1, BigDecimal value2) {
		return (value1.compareTo(value2) < 0);
	}
	
	/**
	 * value 是否有值
	 */
	public static boolean isHaveValue(BigDecimal value) {
		if (value == null) {
			return false;
		}

		if (isEqual(value, BigDecimal.ZERO)) {
			return false;
		}

		return true;
	}
	
	/**
	 * 是否為0(如果傳入null，也會當作是0)
	 */
	public static boolean isZero(BigDecimal value){
		if(value == null){
			return true;
		}
		
		return isEqual(value, BigDecimal.ZERO);
	}

	/**
	 * 是否為正值(大於零)
	 */
	public static boolean isGreaterThanZero(BigDecimal value){
		if(value == null){
			return false;
		}
		
		return isGreater(value, BigDecimal.ZERO);
	}
	
	/**
	 * 是否為負值(不包含0)
	 */
	public static boolean isMinus(BigDecimal value){
		if(value == null){
			return false;
		}
		
		return isLess(value, BigDecimal.ZERO);
	}
	
	/**
	 * 回傳連續加法的結果
	 */
	public static BigDecimal add(BigDecimal ... values){
		BigDecimal result = BigDecimal.ZERO;
		if(values == null || values.length == 0){
			return result;
		}
		
		for(BigDecimal value : values){
			if(value == null){
				continue;
			}
			
			result = add(result, value);
		}
		
		return result;
	}
	
	/**
	 * 回傳連續加法的結果(list)
	 */
	public static BigDecimal addByList(List<BigDecimal> values){
		BigDecimal result = BigDecimal.ZERO;
		if(values == null || values.size() == 0){
			return result;
		}
		
		for(BigDecimal value : values){
			if(value == null){
				continue;
			}
			
			result = add(result, value);
		}
		
		return result;
	}
}
